#    Tichy
#    copyright 2008 Guillaume Chereau (charlie137@gmail.com)
#
#    This file is part of Tichy.
#
#    Tichy is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Tichy is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Tichy.  If not, see <http://www.gnu.org/licenses/>.

import pygame
import pygame.image
import pygame.font
import pygame.locals

from geo import Vect, Rect, asvect, asrect
from painter import Painter
from tichy.tasklet import Tasklet, Wait
from tichy.object import Object

from font import Font

import logging
logger = logging.getLogger('sdl_display')


class SdlPainter(Painter):
    """ Painter Engine that use SDL for rendering

    SDL can be used with X11, or direct frame buffer.  It only offers
    simple blitting functions, but do it very efficiently.
    """

    def __init__(self, size, fullscreen=False):
        Painter.__init__(self, Vect(0, 0), Rect((0, 0), size))
        self.fullscreen = fullscreen
        self.size = size
        pygame.display.init()
        pygame.font.init()
        flags = pygame.FULLSCREEN if fullscreen else 0
        flags |= pygame.RESIZABLE
        self.surface = pygame.display.set_mode(size, flags)
        pygame.display.set_caption("Tichy")

    def toggle_fullscreen(self):
        """Toggle fullscreen on and off

        This is still experimental.
        """
        logger.info("toggle fullscreen")
        self.fullscreen = ~self.fullscreen
        pygame.display.toggle_fullscreen()

    def to_surface(self, surface):
        """Return a engine similar to this one but
        drawing into a given surface"""
        ret = SdlPainter.__new__(SdlPainter)
        ret.pos = Vect(0, 0)
        ret.mask = Rect((0, 0), surface.get_size())
        ret.surface = surface
        return ret

    def set_mask(self, mask):
        super(SdlPainter, self).set_mask(mask)
        rr = self.mask.move(self.pos)
        self.surface.set_clip((rr.pos.x, rr.pos.y, rr.size.x, rr.size.y))

    def clip(self, r):
        super(SdlPainter, self).clip(r)
        self.surface.set_clip(self.mask.move(self.pos).to_list())

    def surface_from_size(self, size):
        # This is not really optimized, because we use transparent
        # surface all the time
        return pygame.Surface(size, pygame.SRCALPHA, 32).convert_alpha()

    def surface_from_svg(self, path):
        import rsvg
        import cairo
        import array
        # NOTE: currently pygame has a bug where it switches channel
        # in the buffer before drawing it. The fix below is
        # inefficient and is not being included for now. So the svg
        # colors will be off

        # commented out pygame channel switch bug
        #
        #import re
        # create pygame image surface
        # there is a bug in pygame where it switches buffer channels
        # r"\2\1\4\3"
        #fixed_buf = re.sub (r"(.)(.)(.)(.)", r"\4\3\2\1", buf.tostring())
        #surf = pygame.image.fromstring(fixed_buf, (width,height), "ARGB")

        svg = rsvg.Handle(file=path)
        width, height = svg.props.width, svg.props.width
        stride = width * 4
        # create a character data structure because pycairo does not
        # seem to handle python types
        buf = array.array('c', chr(0) * width * height * 4)
        cairo_surface = cairo.ImageSurface.create_for_data(
            buf, cairo.FORMAT_ARGB32, width, height, stride)
        cairo_context = cairo.Context(cairo_surface)
        svg.render_cairo(cairo_context)
        surf = pygame.image.frombuffer(buf.tostring(),
                                       (width, height), "ARGB")
        return surf.convert_alpha()

    def surface_from_image(self, path):
        if path[-3:] == 'svg':
            try:
                return self.surface_from_svg(path)
            except Exception, e:
                logger.error("can't use surface_from_svg : %s", e)
        surf = pygame.image.load(path)
        return surf.convert_alpha()

    def draw_text(self, text, font, color):
        surf = font.render(self, text, color)
        self.surface.blit(surf, (self.pos.x, self.pos.y))
        return Vect(surf.get_width(), 0)

    def draw_surface(self, surf, area=None):
        if area:
            area = asrect(area)
            self.surface.blit(surf, self.pos.to_list(), area.to_list())
        else:
            self.surface.blit(surf, self.pos.to_list())

    def fill(self, color, size=None):
        if size:
            self.surface.fill(color,
                              (self.pos.x, self.pos.y, size[0], size[1]))
        else:
            self.surface.fill(color)

    def flip(self, rect=None):
        if not rect:
            pygame.display.flip()
        else:
            pygame.display.update(rect.to_list())

    def _fill_pattern(self, surf, src_x, src_y, src_w, src_h,
                      dst_x, dst_y, dst_w, dst_h):
        src = pygame.Rect(src_x, src_y, src_w, src_h)
        dst = pygame.Rect(0, 0, dst_w, dst_h)

        x = 0
        y = 0

        while y < dst.h:
            dst.y = self.pos.y + dst_y + y
            x = 0
            while x < dst.w:
                dst.x = self.pos.x + dst_x + x
                self.surface.blit(surf, dst, src)
                x += src_w
            y += src_h

    def draw_frame(self, frame, size):
        width, height = size.x, size.y
        frame.image.load(self)
        surface = frame.image.surf

        w2 = width / 2 - 8
        h2 = height / 2 - 8

        fill = self._fill_pattern

        fill(surface, 8, 8, 8, 8, 8, 8, w2, h2)
        fill(surface, 16, 8, 8, 8, 8 + w2, 8, w2, h2)
        fill(surface, 8, 16, 8, 8, 8, 8 + h2, w2, h2)
        fill(surface, 16, 16, 8, 8, 8 + w2, 8 + h2, w2, h2)

        fill(surface, 8, 0, 8, 8, 8, 0, w2, 8)
        fill(surface, 16, 0, 8, 8, 8 + w2, 0, w2, 8)

        fill(surface, 8, 24, 8, 8, 8, height - 8, w2, 8)
        fill(surface, 16, 24, 8, 8, 8 + w2, height - 8, w2, 8)

        fill(surface, 0, 8, 8, 8, 0, 8, 8, h2)
        fill(surface, 0, 16, 8, 8, 0, 8 + h2, 8, h2)

        fill(surface, 24, 8, 8, 8, width - 8, 8, 8, h2)
        fill(surface, 24, 16, 8, 8, width - 8, 8 + h2, 8, h2)

        fill(surface, 0, 0, 8, 8, 0, 0, 8, 8)
        fill(surface, 24, 0, 8, 8, width - 8, 0, 8, 8)
        fill(surface, 0, 24, 8, 8, 0, height - 8, 8, 8)
        fill(surface, 24, 24, 8, 8, width - 8, height - 8, 8, 8)
